From 00b7f63bd7bd400d9fdf92974c5e295b30ba1d2f Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Fri, 14 Aug 2015 15:20:42 -0500
Subject: [PATCH 01/45] southbridge/amd/sr5650: Add MCFG ACPI table support

Change-Id: I0c4ba74ddcc727cd92b848d5d3240e6f9f392101
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/northbridge/amd/amdfam10/northbridge.c |  22 +++---
 src/southbridge/amd/rs780/rs780.c          |  11 +++
 src/southbridge/amd/rs780/rs780.h          |   1 +
 src/southbridge/amd/sb700/lpc.c            |   6 --
 src/southbridge/amd/sb800/lpc.c            |   7 +-
 src/southbridge/amd/sr5650/Kconfig         |   9 +++
 src/southbridge/amd/sr5650/ht.c            | 107 ++++++++++++++++++++++++++++-
 src/southbridge/amd/sr5650/sr5650.c        |  18 +++++
 8 files changed, 156 insertions(+), 25 deletions(-)

diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c
index c8bf8fa..b376171 100644
--- a/src/northbridge/amd/amdfam10/northbridge.c
+++ b/src/northbridge/amd/amdfam10/northbridge.c
@@ -737,16 +737,18 @@ static void amdfam10_domain_read_resources(device_t dev)
 
 	pci_domain_read_resources(dev);
 
-#if CONFIG_MMCONF_SUPPORT
-	struct resource *res = new_resource(dev, 0xc0010058);
-	res->base = CONFIG_MMCONF_BASE_ADDRESS;
-	res->size = CONFIG_MMCONF_BUS_NUMBER * 4096*256;
-	res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
-		IORESOURCE_FIXED | IORESOURCE_STORED |  IORESOURCE_ASSIGNED;
-
-	/* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
-	ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
-#endif
+	if (IS_ENABLED(CONFIG_MMCONF_SUPPORT) && !IS_ENABLED(CONFIG_EXT_CONF_SUPPORT)) {
+		struct resource *res = new_resource(dev, 0xc0010058);
+		res->base = CONFIG_MMCONF_BASE_ADDRESS;
+		res->size = CONFIG_MMCONF_BUS_NUMBER * 4096*256;
+		res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE |
+			IORESOURCE_FIXED | IORESOURCE_STORED |  IORESOURCE_ASSIGNED;
+	}
+
+	if (IS_ENABLED(CONFIG_MMCONF_SUPPORT)) {
+		/* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
+		ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
+	}
 
 	if (is_fam15h()) {
 		enable_cc6 = 0;
diff --git a/src/southbridge/amd/rs780/rs780.c b/src/southbridge/amd/rs780/rs780.c
index c82a629..0d482ae 100644
--- a/src/southbridge/amd/rs780/rs780.c
+++ b/src/southbridge/amd/rs780/rs780.c
@@ -349,6 +349,17 @@ void rs780_enable(device_t dev)
 	}
 }
 
+#if !IS_ENABLED(CONFIG_AMD_SB_CIMX)
+unsigned long acpi_fill_mcfg(unsigned long current)
+{
+	/* FIXME
+	 * Leave table blank until proper contents
+	 * are determined.
+	 */
+	return current;
+}
+#endif
+
 struct chip_operations southbridge_amd_rs780_ops = {
 	CHIP_NAME("ATI RS780")
 	.enable_dev = rs780_enable,
diff --git a/src/southbridge/amd/rs780/rs780.h b/src/southbridge/amd/rs780/rs780.h
index 341de0d..abc601f 100644
--- a/src/southbridge/amd/rs780/rs780.h
+++ b/src/southbridge/amd/rs780/rs780.h
@@ -17,6 +17,7 @@
 #define __RS780_H__
 
 #include <stdint.h>
+#include <arch/acpi.h>
 #include <device/pci_ids.h>
 #include "chip.h"
 #include "rev.h"
diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c
index a71fe1f..78933fa 100644
--- a/src/southbridge/amd/sb700/lpc.c
+++ b/src/southbridge/amd/sb700/lpc.c
@@ -30,12 +30,6 @@
 #include <cpu/amd/powernow.h>
 #include "sb700.h"
 
-unsigned long acpi_fill_mcfg(unsigned long current)
-{
-       /* Just a dummy */
-       return current;
-}
-
 static void lpc_init(device_t dev)
 {
 	u8 byte;
diff --git a/src/southbridge/amd/sb800/lpc.c b/src/southbridge/amd/sb800/lpc.c
index 756a0c4..18d4471 100644
--- a/src/southbridge/amd/sb800/lpc.c
+++ b/src/southbridge/amd/sb800/lpc.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,12 +26,6 @@
 #include <arch/acpi.h>
 #include "sb800.h"
 
-unsigned long acpi_fill_mcfg(unsigned long current)
-{
-       /* Just a dummy */
-       return current;
-}
-
 static void lpc_init(device_t dev)
 {
 	u8 byte;
diff --git a/src/southbridge/amd/sr5650/Kconfig b/src/southbridge/amd/sr5650/Kconfig
index 29017c6..f2d12ff 100644
--- a/src/southbridge/amd/sr5650/Kconfig
+++ b/src/southbridge/amd/sr5650/Kconfig
@@ -15,3 +15,12 @@
 
 config SOUTHBRIDGE_AMD_SR5650
 	bool
+
+if SOUTHBRIDGE_AMD_SR5650
+config EXT_CONF_SUPPORT
+	bool "Enable PCI-E MMCONFIG support"
+	default n
+	help
+	  Select to enable PCI-E MMCONFIG support on the SR5650.
+
+endif
diff --git a/src/southbridge/amd/sr5650/ht.c b/src/southbridge/amd/sr5650/ht.c
index 6119985..e74d36b 100644
--- a/src/southbridge/amd/sr5650/ht.c
+++ b/src/southbridge/amd/sr5650/ht.c
@@ -20,7 +20,9 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/ioapic.h>
+#include <lib.h>
 #include "sr5650.h"
+#include "cmn.h"
 
 /* Table 6-6 Recommended Interrupt Routing Configuration */
 typedef struct _apic_device_info {
@@ -154,11 +156,29 @@ static void pcie_init(struct device *dev)
 
 static void sr5690_read_resource(struct device *dev)
 {
+	struct resource *res;
+
+	if (IS_ENABLED(CONFIG_EXT_CONF_SUPPORT)) {
+		printk(BIOS_DEBUG,"%s: %s\n", __func__, dev_path(dev));
+		set_nbmisc_enable_bits(dev, 0x0, 1 << 3, 1 << 3);	/* Hide BAR3 */
+	}
+
 	pci_dev_read_resources(dev);
 
 	/* rpr6.2.(1). Write the Base Address Register (BAR) */
-	pci_write_config32(dev, 0xF8, 0x1); /* set IOAPIC's index as 1 and make sure no one changes it. */
-	pci_get_resource(dev, 0xFC); /* APIC located in sr5690 */
+	pci_write_config32(dev, 0xf8, 0x1);	/* Set IOAPIC's index to 1 and make sure no one changes it */
+	pci_get_resource(dev, 0xfc);		/* APIC located in sr5690 */
+
+	if (IS_ENABLED(CONFIG_EXT_CONF_SUPPORT)) {
+		res = new_resource(dev, 0x1c);		/* PCIe MCFG space */
+		res->base = EXT_CONF_BASE_ADDRESS;
+		res->size = CONFIG_MMCONF_BUS_NUMBER * 1024 * 1024;	/* Each bus needs 1M */
+		res->align = log2(res->size);
+		res->gran = log2(res->size);
+		res->limit = 0xffffffffffffffffULL;	/* 64-bit location allowed */
+		res->flags = IORESOURCE_FIXED | IORESOURCE_MEM | IORESOURCE_PCI64
+				| IORESOURCE_ASSIGNED | IORESOURCE_RESERVE | IORESOURCE_BRIDGE;
+	}
 
 	compact_resources(dev);
 }
@@ -166,7 +186,88 @@ static void sr5690_read_resource(struct device *dev)
 /* If IOAPIC's index changes, we should replace the pci_dev_set_resource(). */
 static void sr5690_set_resources(struct device *dev)
 {
-	pci_write_config32(dev, 0xF8, 0x1); /* set IOAPIC's index as 1 and make sure no one changes it. */
+	pci_write_config32(dev, 0xf8, 0x1); /* Set IOAPIC's index to 1 and make sure no one changes it */
+
+	if (IS_ENABLED(CONFIG_EXT_CONF_SUPPORT)) {
+		uint32_t reg;
+		device_t amd_ht_cfg_dev;
+		device_t amd_addr_map_dev;
+		resource_t res_base;
+		resource_t res_end;
+		uint32_t base;
+		uint32_t limit;
+		struct resource *res;
+
+		printk(BIOS_DEBUG,"%s %s\n", dev_path(dev), __func__);
+
+		res = probe_resource(dev, 0x1c);
+		if (res) {
+			/* Find requisite AMD CPU devices */
+			amd_ht_cfg_dev = dev_find_slot(0, PCI_DEVFN(0x18, 0));
+			amd_addr_map_dev = dev_find_slot(0, PCI_DEVFN(0x18, 1));
+
+			if (!amd_ht_cfg_dev || !amd_addr_map_dev) {
+				printk(BIOS_WARNING, "%s: %s Unable to locate CPU control devices\n", __func__, dev_path(dev));
+			}
+			else {
+				/* Set up MMCONFIG bus range */
+				set_nbmisc_enable_bits(dev, 0x0, 1 << 3, 0 << 3);	/* Make BAR3 visible */
+				set_nbcfg_enable_bits(dev, 0x7c, 1 << 30, 1 << 30);	/* Enables writes to the BAR3 register */
+				set_nbcfg_enable_bits(dev, 0x84, 7 << 16, 0 << 16);	/* Program bus range = 255 busses */
+				pci_write_config32(dev, 0x1c, res->base);
+
+				/* Enable MMCONFIG decoding. */
+				set_htiu_enable_bits(dev, 0x32, 1 << 28, 1 << 28);	/* PCIEMiscInit */
+				set_nbcfg_enable_bits(dev, 0x7c, 1 << 30, 0 << 30);	/* Disable writes to the BAR3 register */
+				set_nbmisc_enable_bits(dev, 0x0, 1 << 3, 1 << 3);	/* Hide BAR3 */
+
+				/* Set up nonposted resource in MMIO space */
+				res_base = res->base;		/* Get the base address */
+				res_end = resource_end(res);	/* Get the limit (rounded up) */
+				printk(BIOS_DEBUG, "%s: %s[0x1c] base = %0llx limit = %0llx\n", __func__, dev_path(dev), res_base, res_end);
+
+				/* Locate an unused MMIO resource */
+				for (reg = 0xb8; reg >= 0x80; reg -= 8) {
+					base = pci_read_config32(amd_addr_map_dev, reg);
+					limit = pci_read_config32(amd_addr_map_dev, reg + 4);
+					if (!(base & 0x3))
+						break;	/* Unused resource found */
+				}
+
+				/* If an unused MMIO resource was available, set up the mapping */
+				if (!(base & 0x3)) {
+					uint32_t sblk;
+
+					/* Remember this resource has been stored. */
+					res->flags |= IORESOURCE_STORED;
+					report_resource_stored(dev, res, " <mmconfig>");
+
+					/* Get SBLink value (HyperTransport I/O Hub Link ID). */
+					sblk = (pci_read_config32(amd_ht_cfg_dev, 0x64) >> 8) & 0x3;
+
+					/* Calculate the MMIO mapping base */
+					base &= 0x000000f0;
+					base |= ((res_base >> 8) & 0xffffff00);
+					base |= 3;
+
+					/* Calculate the MMIO mapping limit */
+					limit &= 0x00000048;
+					limit |= ((res_end >> 8) & 0xffffff00);
+					limit |= (sblk << 4);
+					limit |= (1 << 7);
+
+					/* Configure and enable MMIO mapping */
+					printk(BIOS_INFO, "%s: %s <- index %x base %04x limit %04x\n", __func__, dev_path(amd_addr_map_dev), reg, base, limit);
+					pci_write_config32(amd_addr_map_dev, reg + 4, limit);
+					pci_write_config32(amd_addr_map_dev, reg, base);
+				}
+				else {
+					printk(BIOS_WARNING, "%s: %s No free MMIO resources available\n", __func__, dev_path(dev));
+				}
+			}
+		}
+	}
+
 	pci_dev_set_resources(dev);
 }
 
diff --git a/src/southbridge/amd/sr5650/sr5650.c b/src/southbridge/amd/sr5650/sr5650.c
index 07b4a02..54f0071 100644
--- a/src/southbridge/amd/sr5650/sr5650.c
+++ b/src/southbridge/amd/sr5650/sr5650.c
@@ -796,6 +796,24 @@ static void add_ivrs_device_entries(struct device *parent, struct device *dev, i
 	free(root_level);
 }
 
+unsigned long acpi_fill_mcfg(unsigned long current)
+{
+	struct resource *res;
+	resource_t mmconf_base = EXT_CONF_BASE_ADDRESS;
+
+	if (IS_ENABLED(CONFIG_EXT_CONF_SUPPORT)) {
+		device_t dev = dev_find_slot(0, PCI_DEVFN(0, 0));
+		/* Report MMCONF base */
+		res = probe_resource(dev, 0x1c);
+		if (res)
+			mmconf_base = res->base;
+
+		current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current, mmconf_base, 0x0, 0x0, 0x1f);
+	}
+
+	return current;
+}
+
 static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current)
 {
 	uint8_t *p;
-- 
2.1.4

